﻿
var regionSources = {
    afghanistan: { x: 709, y: 232, name: 'Afghanistan', connections: ['ukraine', 'ural', 'china', 'india', 'middle_east'] },
    alaska: { x: 53, y: 94, name: 'Alaska', connections: ['alberta', 'northwest_territory', 'kamchatka'] },
    alberta: { x: 146, y: 155, name: 'Alberta', connections: ['alaska', 'northwest_territory', 'ontario', 'western_united_states'] },
    argentina: { x: 275, y: 542, name: 'Argentina', connections: ['peru', 'brasil'] },
    brasil: { x: 260, y: 439, name: 'Brazil', connections: ['peru', 'venezuela', 'argentina', 'north_africa'] },
    central_america: { x: 162, y: 312, name: 'Central America', connections: ['eastern_united_states', 'western_united_states', 'venezuela'] },
    china: { x: 811, y: 254, name: 'China', connections: ['mongolia', 'siberia', 'ural', 'afghanistan', 'india', 'siam'] },
    congo: { x: 571, y: 516, name: 'Congo', connections: ['north_africa', 'south_africa', 'east_africa'] },
    eastern_australia: { x: 1014, y: 577, name: 'Eastern Australia', connections: ['western_australia', 'new_guinea'] },
    eastern_united_states: { x: 214, y: 230, name: 'Eastern United States', connections: ['quebec', 'ontario', 'western_united_states', 'central_america'] },
    east_africa: { x: 625, y: 467, name: 'East Africa', connections: ['middle_east', 'egypt', 'north_africa', 'congo', 'south_africa', 'madagascar'] },
    egypt: { x: 573, y: 411, name: 'Egypt', connections: ['middle_east', 'southern_europe', 'north_africa', 'east_africa'] },
    great_britain: { x: 440, y: 199, name: 'Great Britain', connections: ['iceland', 'scandinavia', 'northern_europe', 'western_europe'] },
    greenland: { x: 330, y: 39, name: 'Greenland', connections: ['iceland', 'quebec', 'ontario', 'northwest_territory'] },
    iceland: { x: 470, y: 148, name: 'Iceland', connections: ['great_britain', 'greenland', 'scandinavia'] },
    india: { x: 773, y: 332, name: 'India', connections: ['middle_east', 'afghanistan', 'china', 'siam'] },
    indonesia: { x: 878, y: 511, name: 'Indonesia', connections: ['siam', 'new_guinea', 'western_australia'] },
    irkutsk: { x: 862, y: 152, name: 'Irkutsk', connections: ['yakutsk', 'kamchatka', 'mongolia', 'siberia'] },
    japan: { x: 1002, y: 214, name: 'Japan', connections: ['kamchatka', 'mongolia'] },
    kamchatka: { x: 938, y: 85, name: 'Kamchatka', connections: ['alaska', 'irkutsk', 'yakutsk', 'japan', 'mongolia'] },
    madagascar: { x: 706, y: 621, name: 'Madagascar', connections: ['east_africa', 'south_africa'] },
    middle_east: { x: 622, y: 344, name: 'Middle East', connections: ['india', 'afghanistan', 'ukraine', 'southern_europe', 'egypt', 'east_africa'] },
    mongolia: { x: 871, y: 217, name: 'Mongolia', connections: ['irkutsk', 'japan', 'kamchatka', 'siberia', 'china'] },
    new_guinea: { x: 990, y: 500, name: 'New Guinea', connections: ['eastern_australia', 'western_australia', 'indonesia'] },
    northern_europe: { x: 531, y: 213, name: 'Northern Europe', connections: ['ukraine', 'scandinavia', 'great_britain', 'western_europe', 'southern_europe'] },
    northwest_territory: { x: 134, y: 79, name: 'Northwest Territory', connections: ['greenland', 'alaska', 'alberta', 'ontario'] },
    north_africa: { x: 475, y: 390, name: 'North Africa', connections: ['western_europe', 'southern_europe', 'egypt', 'east_africa', 'congo', 'brasil'] },
    ontario: { x: 235, y: 158, name: 'Ontario', connections: ['greenland', 'northwest_territory', 'alberta', 'western_united_states', 'eastern_united_states', 'quebec'] },
    peru: { x: 235, y: 456, name: 'Peru', connections: ['venezuela', 'brasil', 'argentina'] },
    quebec: { x: 303, y: 153, name: 'Quebec', connections: ['greenland', 'ontario', 'eastern_united_states'] },
    scandinavia: { x: 542, y: 111, name: 'Scandinavia', connections: ['iceland', 'ukraine', 'northern_europe', 'great_britain'] },
    siam: { x: 882, y: 390, name: 'Siam', connections: ['china', 'india', 'indonesia'] },
    siberia: { x: 777, y: 52, name: 'Siberia', connections: ['yakutsk', 'irkutsk', 'mongolia', 'china', 'ural'] },
    southern_europe: { x: 540, y: 286, name: 'Southern Europe', connections: ['ukraine', 'northern_europe', 'western_europe', 'north_africa', 'egypt', 'middle_east'] },
    south_africa: { x: 584, y: 589, name: 'South Africa', connections: ['congo', 'east_africa', 'madagascar'] },
    ukraine: { x: 608, y: 114, name: 'Ukraine', connections: ['scandinavia', 'northern_europe', 'southern_europe', 'middle_east', 'afghanistan', 'ural'] },
    ural: { x: 754, y: 86, name: 'Ural', connections: ['china', 'siberia', 'afghanistan', 'ukraine'] },
    venezuela: { x: 241, y: 405, name: 'Venezuela', connections: ['central_america', 'peru', 'brasil'] },
    western_australia: { x: 940, y: 593, name: 'Western Australia', connections: ['eastern_australia', 'new_guinea', 'indonesia'] },
    western_europe: { x: 464, y: 286, name: 'Western Europe', connections: ['great_britain', 'northern_europe', 'southern_europe', 'north_africa'] },
    western_united_states: { x: 152, y: 229, name: 'Western United States', connections: ['alberta', 'ontario', 'eastern_united_states', 'central_america'] },
    yakutsk: { x: 879, y: 68, name: 'Yakutsk', connections: ['kamchatka', 'irkutsk', 'siberia'] }
};
var mapSources = {
    connections: 'connections.png',
    dice: 'dice.png',
    button: 'button.png',
    attack: 'attack.png',
    move: 'move.png'
}

/// GameUI class
function GameUI() {
    this.stage = null;
    this.troopElements = {};
    this.playerElements = [];
    this.regionElements = [];
    this.diceChoiceElements = [];
    this.dice = [];
    this.moveChoiceElements = [];

    this.information = null;

    this.regions = {};
    this.images = {};

    this.hoveredGroup = null;
    this.startGroup = null;
    this.tempMovement = null;

    this.mapLayer = new Kinetic.Layer();
    this.regionLayer = new Kinetic.Layer();
    this.interfaceLayer = new Kinetic.Layer();
    this.messageLayer = new Kinetic.Layer();
    this.armyLayer = new Kinetic.Layer();
    this.movementLayer = new Kinetic.Layer();
}
GameUI.prototype.loadResources = function () {
    var self = this;
    // clear resources
    this.regions = {};
    this.images = {};
    var loadedImages = 0;
    var numImages = 0;
    for (var src in regionSources) {
        numImages++;
    }
    for (var src in mapSources) {
        numImages++;
    }
    for (var src in regionSources) {
        var o = regionSources[src];
        this.regions[src] = { image: new Image(), x: o.x, y: 80+o.y, name: o.name, id: src, connections: o.connections };
        this.regions[src].image.onload = function () {
            if (++loadedImages >= numImages) {
                self.draw();
            }
        };
        this.regions[src].image.src = srcDir + src+'.png';
    }
    for (var src in mapSources) {
        this.images[src] = new Image();
        this.images[src].onload = function () {
            if (++loadedImages >= numImages) {
                self.draw();
            }
        };
        this.images[src].src = srcDir+mapSources[src];
    }
}
GameUI.prototype.draw = function () {
    this.stage = new Kinetic.Stage({
        container: 'map',
        width: 1350,
        height: 846
    });
    var connectionsImage = new Kinetic.Image({
        image: this.images.connections
    });
    this.mapLayer.add(connectionsImage);
    // draw regions
    this.drawRegions();
    // draw player information
    for (var i = 0; i < game.gameData.Players.length; i++) {
        this.drawPlayerInformation(game.gameData.Players[i], i);
    }
    // draw turn information
    this.drawInformation();
    this.stage.add(this.mapLayer);
    this.stage.add(this.regionLayer);
    this.stage.add(this.movementLayer);
    this.stage.add(this.armyLayer);
    this.stage.add(this.messageLayer);
    this.stage.add(this.interfaceLayer);
    this.update();
}
GameUI.prototype.update = function () {
    // show turn information
    if (game.isMyTurn()) {
        this.information.title.show();
        this.information.btn.show();
        this.information.btnText.show();
        this.information.title.setText(game.getInstruction());
        this.information.btnText.setText(game.getButtonLabel());
    } else {
        this.information.title.hide();
        this.information.btn.hide();
        this.information.btnText.hide();
    }
    // update information
    var army = game.getMyArmy();
    this.information.reserve.setText("reserve: " + army.Reserve.toString());
    this.information.bonus.setText("bonus: " + army.Bonus.toString());
    // put active user in bold
    for (var i = 0; i < this.playerElements.length; i++) {
        var element = this.playerElements[i];
        var style = game.isPlayerTurn(element.player.Id) ? 'bold' : 'normal';
        element.nameElement.setFontStyle(style);
    }
    // update the troops
    for (var regionId in game.troops) {
        var troop = game.troops[regionId];
        var troopElement = this.troopElements[regionId];
        if (troopElement != null) {
            troopElement.numberElement.setText(troop.count.toString());
            troopElement.circleElement.setFill(troop.player.Color);
        }
    }
    this.interfaceLayer.draw();
    this.armyLayer.draw();
}
GameUI.prototype.drawRegions = function () {
    var self = this;
    for (var regionId in this.regions) {
        var region = this.regions[regionId];
        // draw the region image
        var regionElement = new Kinetic.Image(region);
        regionElement.region = region;
        regionElement.createImageHitRegion(function () {
            self.regionLayer.drawHit();
        });
        regionElement.on('mouseover', function () {
            self.writeMessage(this.attrs.name);
        });
        regionElement.on('mouseout', function () {
            self.writeMessage('');
        });
        this.regionLayer.add(regionElement);
        this.regionElements.push(regionElement);

        // draw the troop for this region
        this.drawTroop(region);
    }
    this.tempMovement = new Kinetic.Polygon({
        points: [],
        fill: '#00D2FF',
        stroke: 'black',
        strokeWidth: 2,
        drawHitFunc: function (context) { }
    });
    this.stage.on('mousedown', function () {
        if (self.hoveredGroup != null && game.isMyTurn() && game.getMyState() > 2) {
            self.startGroup = self.hoveredGroup;
            self.movementLayer.add(self.tempMovement);
        }
    });
    this.stage.on('mouseup', function (evt) {
        if (self.hoveredGroup != null && self.startGroup != null && self.startGroup.region != self.hoveredGroup.region) {
            if (game.getMyState() == 3) {
                game.prepareAttack(self.startGroup.region.id, self.hoveredGroup.region.id, "How many dice do you want to use?");
            } else if (game.getMyState() == 4) {
                game.prepareMove(self.startGroup.region.id, self.hoveredGroup.region.id, "How many do you want to move?");
            }
            evt.cancelBubble = true;
        }
        self.startGroup = null;
        self.movementLayer.clear();
    });
    this.stage.on('mousemove', function () {
        if (self.startGroup != null && self.tempMovement != null) {
            var mousePos = this.getMousePosition();
            var attrs = self.startGroup.children[0].attrs;
            var angle = Math.atan((mousePos.x - attrs.x) / (mousePos.y - attrs.y));
            var ddx = Math.cos(angle) * 15;
            var ddy = Math.sin(angle) * 15;
            var points = [attrs.x - ddx, attrs.y + ddy, mousePos.x, mousePos.y, attrs.x + ddx, attrs.y - ddy];
            self.tempMovement.setPoints(points);
            self.movementLayer.draw();
        }
    });
}
GameUI.prototype.drawPlayerInformation = function (player, index) {
    var x = 1165;
    var y = 130 + index * 30;
    var colorElement = new Kinetic.Rect({
        x: x, y: y,
        width: 20, height: 16,
        fill: player.Color,
        stroke: 'black',
        strokeWidth: 2
    });
    var nameElement = this.createText(x + 30, y, player.Name, 16);

    this.interfaceLayer.add(colorElement);
    this.interfaceLayer.add(nameElement);
    this.playerElements.push({ player: player, colorElement: colorElement, nameElement: nameElement });
}

GameUI.prototype.clearChoices = function (red, blue) {
    // clear all dice
    for (var k = 0; k < this.dice.length; k++) {
        this.dice[k].destroy();
    }
    this.dice = [];
    // clear all dice choices
    for (var k = 0; k < this.diceChoiceElements.length; k++) {
        this.diceChoiceElements[k].destroy();
    }
    this.diceChoiceElements = [];
    // clear all move counts
    for (var k = 0; k < this.moveChoiceElements.length; k++) {
        this.moveChoiceElements[k].destroy();
    }
    this.moveChoiceElements = [];
}
GameUI.prototype.drawDice = function (red, blue) {
    this.clearChoices();
    // draw dice
    for (var i = 0; i < red.length; i++) {
        this.drawDie(1, red[i], 1020 + i*43, 2);
    }
    for (var i = 0; i < blue.length; i++) {
        this.drawDie(0, blue[i], 1020 + i * 43, 45);
    }
}
GameUI.prototype.drawDie = function (color, value, x, y) {
    var d = 40
    var die = new Kinetic.Image({
        image: this.images.dice,
        width: d,
        height: d,
        x: x,
        y: y,
        crop: {
            x: (value-1) * d,
            y: color * d,
            width: d,
            height: d
        }
    });
    this.interfaceLayer.add(die);
    this.dice.push(die);
}
GameUI.prototype.drawDiceChoices = function (max, from, to, message) {
    this.clearChoices();
    for (var i = 0; i < Math.min(3, max); i++) {
        this.drawDiceChoice(i, 930 + i * 50, 30, from, to);
    }
    var howMany = this.createText(930, 10, message, 14);
    this.interfaceLayer.add(howMany);
    this.diceChoiceElements.push(howMany);
    this.interfaceLayer.draw();
}
GameUI.prototype.drawDiceChoice = function (count, x, y, from, to) {
    var w = 47;
    var h = 50;
    var choice = new Kinetic.Image({
        image: this.images.attack,
        width: w,
        height: h,
        x: x,
        y: y,
        crop: {
            x: count * w,
            y: 0,
            width: w,
            height: h
        }
    });
    choice.on('click', function () {
        game.attack(from, to, count+1);
    });
    choice.on('mouseover', function () {
        document.body.style.cursor = 'pointer';
    });
    choice.on('mouseout', function () {
        document.body.style.cursor = 'default';
    });
    this.interfaceLayer.add(choice);
    this.diceChoiceElements.push(choice);
}
GameUI.prototype.drawMoveChoices = function (max, from, to, message) {
    this.clearChoices();
    var counts = [0, 1, 2, 3, 4, 5, 10];
    var i = 0;
    for(; i < counts.length && counts[i] <= max ; i++) {
        this.drawMoveChoice(i, counts[i], 850 + i * 33, 30, from, to);
    }
    this.drawMoveChoice(7, max, 850 + i * 33, 30, from, to);
    var howMany = this.createText(850, 10, message, 14);
    this.interfaceLayer.add(howMany);
    this.moveChoiceElements.push(howMany);
    this.interfaceLayer.draw();
}
GameUI.prototype.drawMoveChoice = function (i, count, x, y, from, to) {
    var d = 30;
    var choice = new Kinetic.Image({
        image: this.images.move,
        width: d,
        height: d,
        x: x,
        y: y,
        crop: {
            x: i*d,
            y: 0,
            width: d,
            height: d
        }
    });
    choice.on('click', function () {
        game.gui.clearChoices();
        game.move(from, to, count);
    });
    choice.on('mouseover', function () {
        document.body.style.cursor = 'pointer';
    });
    choice.on('mouseout', function () {
        document.body.style.cursor = 'default';
    });
    this.interfaceLayer.add(choice);
    this.moveChoiceElements.push(choice);
}
GameUI.prototype.drawInformation = function () {
    var title = this.createText(0, 10, "", 23, true, true, 1154);
    var btnText = this.createText(0, 50, "Done", 16, true, true, 1154, true);
    var reserve = this.createText(1165, 500 ,"", 17);
    var bonus = this.createText(1165, 525, "", 17);
    var btn = new Kinetic.Image({
        image: this.images.button,
        x: 485,
        y: 45
    });

    btn.on('click', function () {
        game.gui.clearChoices();
        game.stageDone();
    });
    btn.on('mouseover', function () {
        document.body.style.cursor = 'pointer';
    });
    btn.on('mouseout', function () {
        document.body.style.cursor = 'default';
    });
    this.interfaceLayer.add(title);
    this.interfaceLayer.add(reserve);
    this.interfaceLayer.add(bonus);
    this.interfaceLayer.add(btn);
    this.interfaceLayer.add(btnText);
    this.information = {title: title, reserve: reserve, bonus: bonus, btn: btn, btnText: btnText};
}
GameUI.prototype.createText = function(x, y, text, size, bold, center, width, noMouse, font){
    return new Kinetic.Text({
        x: x, y: y,
        text: text,
        fontSize: size,
        fontFamily: font == null ? 'Candara' : font,
        fill: '#000',
        width: width,
        align: center ? 'center' : 'left',
        fontStyle: bold ? 'bold' : 'normal',
        drawHitFunc: noMouse ? function (context) { } : null
    });
}
GameUI.prototype.drawTroop = function (region) {
    var self = this;
    var circleElement = new Kinetic.Circle({
        x: region.x + region.image.width / 2,
        y: region.y + region.image.height / 2,
        radius: 15,
        fill: game.troops[region.id].player.Color,
        stroke: 'black',
        strokeWidth: 2,
    });
    var numberElement = this.createText(
        region.x + region.image.width / 2 - 15,
        region.y + region.image.height / 2 - 15 + 7,
        game.troops[region.id].count.toString(),
        16, true, true, 30, true, 'Calibri');
    var group = new Kinetic.Group({});
    group.region = region; // keep a reference to the region
    group.on('mouseover', function () {
        document.body.style.cursor = 'pointer';
        circleElement.setScale(1.5);
        self.armyLayer.draw();
        self.hoveredGroup = this;
        self.writeMessage(this.region.name);
    });
    group.on('mouseout', function () {
        document.body.style.cursor = 'default';
        circleElement.setScale(1);
        self.armyLayer.draw();
        self.hoveredGroup = null;
        self.writeMessage('');
    });
    group.on('click', function () {
        if (game.isMyTurn() && (game.getMyState() == 1 || game.getMyState() == 2)) {
            game.addTroop(this.region.id);
        }
    });
    group.add(circleElement);
    group.add(numberElement);
    this.armyLayer.add(group);
    this.troopElements[region.id] = { groupElement: group, circleElement: circleElement, numberElement: numberElement };
}
GameUI.prototype.writeMessage = function(message) {
    var context = this.messageLayer.getContext();
    this.messageLayer.clear();
    context.font = '15pt Candara';
    context.fillStyle = 'black';
    context.fillText(message, 20, 120);
}
/// Troop class
function Troop(player, count) {
    this.player = player;
    this.count = count;
}
Troop.prototype.isOwner = function (playerId) {
    return this.player.Id == playerId;
}
/// Game class
function Game() {
    this.gui = new GameUI();
    this.gameData = null;
    this.playerId = null;
    this.troops = {};
    this.load();
}
Game.prototype.update = function (gameData, playerId) {
    this.gameData = gameData;
    this.playerId = playerId;
    this.troops = {};
    for (var i = 0; i < this.gameData.Armies.length; i++) {
        var army = this.gameData.Armies[i];
        for(var j=0; j < army.Troops.length; j++){
            var troop = army.Troops[j];
            this.troops[troop.Region] = new Troop(army.Player, troop.Count);
        }
    }
}
Game.prototype.isMyTurn = function () {
    return this.isPlayerTurn(this.playerId);
}
Game.prototype.isPlayerTurn = function (id) {
    return this.gameData.Players[id].State > 0;
}
Game.prototype.getInstruction = function () {
    switch (this.getMyState()) {
        case 1: return "Place your troops";
        case 2: return "Your turn to reinforce";
        case 3: return "Your turn to attack!";
        case 4: return "Your turn to move a troop";
    }
    return "";
}
Game.prototype.getButtonLabel = function () {
    switch (this.getMyState()) {
        case 1: return "I'm done";
        case 2: return "Done";
        case 3: return "Done";
        case 4: return "End my turn";
    }
    return "";
}
Game.prototype.getMyState = function () {
    return this.gameData.Players[this.playerId].State;
}
Game.prototype.getMyArmy = function () {
    for (var i = 0; i < this.gameData.Armies.length; i++) {
        var army = this.gameData.Armies[i];
        if (army.Player.Id == this.playerId) {
            return army;
        }
    }
    return null;
}
Game.prototype.load = function () {
    $.getJSON("LoadGame", {}, function (data) {
        if (data.game != null) {
            game.update(data.game, data.playerId);
            game.gui.loadResources();
            setInterval(function () { game.refresh() }, 3000);
        } else {
            alert("You need to implement the LoadGame method");
        }
    });
}
Game.prototype.refresh = function (callback) {
    $.getJSON("LoadGame", {}, function (data) {
        if (data.game != null) {
            game.update(data.game, data.playerId);
            game.gui.update();
            if (callback) callback();
        } else {
            alert("You need to implement the LoadGame method");
        }
    });
}
Game.prototype.addTroop = function (regionId) {
    if (this.troops[regionId].isOwner(this.playerId)) {
        $.getJSON("AddTroop", { region: regionId }, function (success) {
            game.refresh();
        });
    }
}
Game.prototype.isConnected = function(a, b){
    var region = this.gui.regions[a];
    for (var j=0; j<region.connections.length; j++) {
        if (region.connections[j] == b) return true;
    }
    return false;
}
Game.prototype.prepareAttack = function (from, to, message) {
    if (this.troops[from].isOwner(this.playerId) && !this.troops[to].isOwner(this.playerId) && this.troops[from].count > 1 && this.isConnected(from, to)) {
        this.gui.drawDiceChoices(this.troops[from].count - 1, from, to, message);
    }
}
Game.prototype.prepareMove = function (from, to, message) {
    if (this.troops[from].isOwner(this.playerId) && this.troops[to].isOwner(this.playerId) && this.troops[from].count > 1 && this.isConnected(from, to)) {
        this.gui.drawMoveChoices(this.troops[from].count - 1, from, to, message);
    }
}
Game.prototype.attack = function (from, to, numberOfDice) {
    $.getJSON("Attack", { from: from, to: to, numberOfDice: numberOfDice }, function (attackResult) {
        if (attackResult != null) {
            game.gui.drawDice(attackResult.Dice, attackResult.DefendingDice);
            game.refresh(function () {
                if (attackResult.Victory) {
                    game.prepareMove(from, to, "Victory! Move more troops?");
                }
            });
        } else {
            alert("You need to implement the Attack method and return a ThrowDTO");
        }
    });
}
Game.prototype.move = function (from, to, number) {
    $.getJSON("Move", { from: from, to: to, number: number }, function (success) {
        game.stageDone();
    });
}
Game.prototype.stageDone = function () {
    $.getJSON("StageDone", { }, function (success) {
        game.refresh();
    });
}